import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { PERMISSIONS_KEY } from '../decorators/permissions.decorator';
import { logPermission } from '../utils/logger';

@Injectable()
export class PermissionsGuard implements CanActivate {
  constructor(private reflector: Reflector) {}

  canActivate(context: ExecutionContext): boolean {
    // 获取请求信息
    const req = context.switchToHttp().getRequest();
    const method = req.method;
    const url = req.url;
    
    // 检查是否标记为公开路由
    const isPublic = this.reflector.getAllAndOverride<boolean>('isPublic', [
      context.getHandler(),
      context.getClass(),
    ]);

    if (isPublic) {
      logPermission(`公开路由: ${method} ${url}`);
      return true;
    }

    const requiredPermissions = this.reflector.getAllAndOverride<string[]>(PERMISSIONS_KEY, [
      context.getHandler(),
      context.getClass(),
    ]);

    if (!requiredPermissions || requiredPermissions.length === 0) {
      logPermission(`无需权限: ${method} ${url}`);
      return true;
    }

    const { user } = context.switchToHttp().getRequest();
    
    // 如果没有用户对象，拒绝访问
    if (!user) {
      logPermission(`权限检查失败: 没有用户信息 - ${method} ${url}`);
      return false;
    }

    // 记录用户信息
    logPermission(`用户请求: ${user.username}(${user.id}) - ${method} ${url}`, {
      requiredPermissions
    });

    // 收集用户的所有权限
    let userPermissions: string[] = [];
    
    // 1. 从角色中获取权限
    if (user.roles) {
      const permissionsFromRoles = user.roles.flatMap((role: any) => {
        // 如果角色是字符串，无法直接获取权限
        if (typeof role === 'string') {
          return [];
        }
        // 对象角色 - 提取permissions属性
        return role.permissions?.map((permission: any) => {
          // 处理权限可能是字符串或对象
          if (typeof permission === 'string') {
            return permission;
          }
          return permission.code || permission.name;
        }) || [];
      });
      userPermissions = userPermissions.concat(permissionsFromRoles);
      
      // 记录角色信息
      logPermission(`用户角色: ${user.username}`, {
        roles: user.roles.map((role: any) => {
          if (typeof role === 'string') return role;
          return role.name || role.code;
        }),
        permissionsFromRoles
      });
    }
    
    // 2. 从JWT令牌中直接获取权限 (这是最可靠的来源)
    if (user.permissions && Array.isArray(user.permissions)) {
      logPermission(`直接从用户对象获取权限: ${user.username}`, {
        directPermissions: user.permissions
      });
      userPermissions = userPermissions.concat(user.permissions);
    }
    
    // 3. 从自定义字段获取权限
    if (user._permissions && Array.isArray(user._permissions)) {
      userPermissions = userPermissions.concat(user._permissions);
      logPermission(`JWT权限(_permissions): ${user.username}`, {
        jwtPermissions: user._permissions
      });
    }
    
    // 4. 如果用户是系统管理员角色，为了调试目的，授予所有权限
    // 增强判断逻辑，同时处理字符串角色和对象角色
    const isAdmin = user.roles?.some((role: any) => {
      // 处理角色既可能是字符串，也可能是对象
      if (typeof role === 'string') {
        return role === '系统管理员' || role === 'admin';
      }
      
      // 处理角色对象，检查name和code属性
      return (role.name === '系统管理员' || role.code === 'admin');
    });
    
    // 添加更详细的日志
    logPermission(`管理员检查: ${user.username}`, {
      roles: user.roles,
      roleTypes: user.roles?.map(r => typeof r),
      isAdmin
    });
    
    if (isAdmin) {
      logPermission(`系统管理员访问: ${user.username} - ${method} ${url}`, {
        roles: user.roles?.map(r => {
          if (typeof r === 'string') return r;
          return r.name || r.code || 'unknown';
        }),
        isAdmin: true
      });
      return true;
    }
    
    // 添加JWT令牌权限检查日志
    logPermission(`JWT令牌权限检查: ${user.username}`, {
      jwt: req.headers.authorization?.substring(0, 30) + '...',
      requiredPermissions,
      userPermissions
    });
    
    // 添加更详细的用户权限详情日志
    logPermission(`用户权限详情: ${user.username}`, {
      roles: user.roles?.map(r => ({ name: r.name, code: r.code })) || [],
      userPermissions,
      requiredPermissions
    });
    
    // 检查权限
    const hasPermission = requiredPermissions.every(permission => userPermissions.includes(permission));
    
    logPermission(`权限检查: ${hasPermission ? '通过' : '拒绝'} - ${method} ${url}`, {
      username: user.username,
      requiredPermissions,
      userPermissions,
      hasPermission
    });

    return hasPermission;
  }
} 